/*  
 *  Copyright (c) 2008 Adrian Macneil
 *  
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

const asPluginId = "tst";

var sbScrobbler = sbScrobbler ? sbScrobbler : {
  launchClient: function() {
    // try user-specified command
    var command = Application.prefs.get("extensions.songbird-scrobbler.command").value;
    if (tryLaunch(command)) {
      return true;
    }
    
    // try getting path from windows registry
    var key = "Software\\Last.fm\\Client";
    
    try {
      var reg = Components.classes["@mozilla.org/windows-registry-key;1"]
                  .createInstance(Components.interfaces.nsIWindowsRegKey);
      reg.open(reg.ROOT_KEY_CURRENT_USER, key, reg.ACCESS_READ);
      command = reg.readStringValue("Path");
      if (tryLaunch(command)) {
        return true;
      }
      reg.close();
    } catch (ex) { }
    
    try {
      var reg = Components.classes["@mozilla.org/windows-registry-key;1"]
                  .createInstance(Components.interfaces.nsIWindowsRegKey);
      reg.open(reg.ROOT_KEY_LOCAL_MACHINE, key, reg.ACCESS_READ);
      command = reg.readStringValue("Path");
      if (tryLaunch(command)) {
        return true;
      }
      reg.close();
    } catch (ex) { }
    
    // try some hard-coded defaults
    var defaults = ["C:\\Program Files\\Last.fm\\LastFM.exe",
                    "/usr/bin/lastfm",
                    "/usr/local/bin/lastfm"];
    for (var d in defaults) {
      if (tryLaunch(defaults[d])) {
        return true;
      }
    }
    
    // give up
    return false;
  },
  
  onLoad: function() {
    // observe changes to play status
    gPPS.addListener(sbScrobbler.playObserver);
    
    // observe changes to pause status
    var pausedRemote = SB_NewDataRemote("faceplate.paused", null);
    pausedRemote.bindObserver(sbScrobbler.pauseObserver, true);
    
    // try launching the last.fm client
    if (Application.prefs.get("extensions.songbird-scrobbler.autolaunch").value) {
      sbScrobbler.launchClient();
    }
  }
}

sbScrobbler.commands = {
  sendCommand: function(cmd) {
    cmd += "\n"; // vital detail
    var host = Application.prefs.get("extensions.songbird-scrobbler.host").value;
    var port = Application.prefs.get("extensions.songbird-scrobbler.port").value;
    
    // get the transport
    var transportService = Components.classes["@mozilla.org/network/socket-transport-service;1"]
          .getService(Components.interfaces.nsISocketTransportService);
    var transport = transportService.createTransport(null, 0, host, port, null);    
    
    // write to the stream
    var outstream = transport.openOutputStream(0, 0, 0);
    outstream.write(cmd, cmd.length);
    outstream.close();
  },

  escapeString: function(cmd) {
    if (cmd == null) return "";
    
    // we need to escape ampersands
    return cmd.replace("&", "&&");
  },

  cmdStart: function(artist, track, album, time, filename) {
    // called when a song starts playing
    var cmd = "START c=" + asPluginId +
              "&a=" + sbScrobbler.commands.escapeString(artist) +
               "&t=" + sbScrobbler.commands.escapeString(track) +
               "&b=" + sbScrobbler.commands.escapeString(album) +
               "&l=" + time +
               "&p=" + sbScrobbler.commands.escapeString(filename);
    sbScrobbler.commands.sendCommand(cmd);
  },

  cmdStop: function() {
    // called when a song is stopped (manually or endsong)
    var cmd = "STOP c=" + asPluginId;
    sbScrobbler.commands.sendCommand(cmd);
  },

  cmdPause: function() {
    // called when a song is manually paused
    var cmd = "PAUSE c=" + asPluginId;
    sbScrobbler.commands.sendCommand(cmd);
  },

  cmdResume: function() {
    // called after a pause to resume playback
    var cmd = "RESUME c=" + asPluginId;
    sbScrobbler.commands.sendCommand(cmd);
  }
}

sbScrobbler.playObserver = {
  onBeforeTrackChange: function() { },  

  onTrackChange: function() {
    // get some info
    var mediaItem = gPPS.playingView.mediaList.getItemByGuid(gPPS.currentGUID);
    
    var artist = mediaItem.getProperty("http://songbirdnest.com/data/1.0#artistName");
    var track = mediaItem.getProperty("http://songbirdnest.com/data/1.0#trackName");
    var album = mediaItem.getProperty("http://songbirdnest.com/data/1.0#albumName");
    var url = gPPS.core.getMetadata("url");
    var time = mediaItem.getProperty("http://songbirdnest.com/data/1.0#duration");
    time = parseInt(time/1000000); // in seconds, please

    // send a start command
    sbScrobbler.commands.cmdStart(artist, track, album, time, url);
  },
  
  onStop: function() {
    // send a stop command
    sbScrobbler.commands.cmdStop();
  }
}

sbScrobbler.pauseObserver = {
  observe: function(aSubject, aTopic, aData) {
    if (aTopic == "faceplate.paused") {
      if (aData == 1) { // a track has been paused
        sbScrobbler.commands.cmdPause();
      }
      else { // a track has been resumed
        sbScrobbler.commands.cmdResume();
      }
    }
  }
}

function tryLaunch(path)
{
  // try to start the Last.fm client from the specified path
  var args = ["--tray"];
  var count = 1;
  
  try {
    var file = Components.classes["@mozilla.org/file/local;1"]
                 .createInstance(Components.interfaces.nsILocalFile);
    file.initWithPath(path);
    
    if (file.exists && file.isExecutable) {
      var process = Components.classes["@mozilla.org/process/util;1"]
                      .createInstance(Components.interfaces.nsIProcess);
      process.init(file);
      process.run(false, args, count);
      return true;
    } else {
      return false;
    }
  } catch (ex) {
    return false;
  }
}

sbScrobbler.onLoad();
